using GLib;
using Posix;
using SerialPort;

public class AutoTestApplication : GLib.Application
{
    private static bool list_ports = false;
    private static bool show_version = false;
    [CCode (array_length = false, array_null_terminated = true)]
    private static string[]? serialports = null;
    private static string? script_file = null;
    private static string? directory = null;
    
    private const GLib.OptionEntry[] options = {
        { "list", 'l', 0, OptionArg.NONE, ref list_ports, "List all available serialports.", null },
        { "port", 'p', 0, OptionArg.STRING_ARRAY, ref serialports, "The serialports will be use.", "COM1/ttyS0." },
        { "file", 'f', 0,  OptionArg.FILENAME, ref script_file, "The script file.", "File" },
        { "directory", 'o', 0,  OptionArg.FILENAME, ref directory, "Logs output directory.", "DIRECTORY" },
	    { "version", 'v', 0, OptionArg.NONE, ref show_version, "Display tool's version", null },
	    { null }
    };

    public AutoTestApplication()
    {
        Object (application_id: "org.matrix.auto_test", flags: ApplicationFlags.HANDLES_COMMAND_LINE);
    }
    
    public override int command_line (ApplicationCommandLine command_line)
    {
		// keep the application running until we are done with this commandline
		this.hold ();
		int res = _command_line (command_line);
		this.release ();
		return res;
	}
    
    private int _command_line (ApplicationCommandLine command_line)
    {
        OptionContext opt_context;
        
		// We have to make an extra copy of the array, since .parse assumes
		// that it can remove strings from the array without freeing them.
		string[] args = command_line.get_arguments ();
		
		string[] _args = new string[args.length];
		
		for (int i = 0; i < args.length; i++) {
			_args[i] = args[i];
		}

		try
		{
			opt_context = new OptionContext ("- SCRIPT_DIR");
			
			opt_context.set_help_enabled (true);
			
			opt_context.add_main_entries (options, null);
			
			unowned string[] tmp = _args;
			
			opt_context.parse (ref tmp);
		}
		catch (OptionError e)
		{
			command_line.print ("error: %s\n", e.message);
			command_line.print ("Run '%s --help' to see a full list of available command line options.\n", args[0]);
			return 0;
		}

        if(list_ports)
        {
            foreach(string name in SerialPortClass.@enum())
            {
                Port port;
                
                Port.new_by_name(name, out port);
                
                if(Transport.USB == port.get_transport())
                {
                    command_line.print ("    --%s: %s, %s\n", name, port.get_description(), port.get_usb_product());
                }
                else
                {
                    command_line.print ("    --%s: Native SerialPort\n", name);
                }
            }
            
            return 0;
        }
		else if (show_version)
		{
			command_line.print ("AutoTest 0.1 Product by Matrix\n");
			return 0;
		}
		else
		{
		    if(0 == serialports.length)
		    {
		        command_line.print(opt_context.get_help(false, null));
		        return 0;
		    }
		}
		
		if(null != directory)
		{
		    if(FileUtils.test(directory, FileTest.EXISTS))
		    {
		        if(!FileUtils.test(directory, FileTest.IS_DIR))
		        {
		            command_line.print ("The argument directory \"%s\" is not valid.\n", directory);
		            return 0;
		        }
		    }
		    else
		    {
		        if(0 != DirUtils.create(directory, 0777))
		        {
		            command_line.print ("Create directory \"%s\" fail.\n", directory);
		            return 0;
		        }
		    }
		}
		
		if(null != script_file)
		{
		    var auto_test = new AutoTest(serialports, script_file, directory);
		
		    auto_test.run();
		}
		else
		{
		    if(null == _args[1])
		    {
		        command_line.print(opt_context.get_help(false, null));
		        return 0;
		    }
		
		    var dir_exploer = new DirExplorer(_args[1:_args.length - 1]);
		
		    foreach(string script_name in dir_exploer)
		    {
		        if(null != script_name)
		        {   
		            var auto_test = new AutoTest(serialports, script_name, directory);
		
		            auto_test.run();
		        }
		    }
        }
		return 0;
	}
}
